﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using TwitterLib;
using System.ComponentModel;
using System.Windows.Threading;
using Pawing.ClickOnce;
using System.Media;
using TwitterLib.Utilities;
using System.Deployment.Application;
using System.Net;
using Snarl;
using Pawing.Misc.Growl;
using System.Text.RegularExpressions;
using TweetSharp.Model;
using Pawing.Properties;
using System.Windows.Media.Animation;
using Pawing.Controls.Search;
using Pawing.Controls.Emotions;
using System.Diagnostics;
using CustomWindow;

namespace Pawing
{
    /// <summary>
    /// DesktopWindow.xaml 的交互逻辑
    /// </summary>
    public partial class DesktopWindow
    {

        #region Fields and Properties

        private IntPtr SnarlConfighWnd;
        private NativeWindowApplication.PawingSnarlMsgWnd snarlComWindow;
        private bool reallyexit = false;


        private static int screenHeight = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
        private static int screenWidth = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width;
        private double proposeHeight = 570;
        private double proposeWidth = 330;


        //for conversation
        private long conversationStartId;

        // Main collection of tweets
        private TweetCollection tweets = new TweetCollection();

        // Main collection of mentions
        private TweetCollection mentions = new TweetCollection();

        private DateTime mentionsLastUpdated;

        private TweetCollection replies = new TweetCollection();
        private DateTime repliesLastUpdated;

        // Main collection of user Tweets
        private TweetCollection userTweets = new TweetCollection();

        // Main collection of "more" Tweets
        private TweetCollection moreTweets = new TweetCollection();

        // Main collection of direct messages
        private DirectMessageCollection messages = new DirectMessageCollection();

        private Dictionary<string, DateTime> ignoredUsers = new Dictionary<string, DateTime>();

        private DateTime messagesLastUpdated;

        // Main TwitterNet object used to make Twitter API calls
        private TwitterNet twitter;

        // Timer used for automatic tweet updates
        private DispatcherTimer refreshTimer = new DispatcherTimer();

        // How often the automatic tweet updates occur.  TODO: Make this configurable
        private TimeSpan refreshInterval;
        private TimeSpan friendsRefreshInterval = new TimeSpan(0, 45, 0);

        private DispatcherTimer friendsRefreshTimer = new DispatcherTimer();

        private DateTime lastFriendsUpdate = DateTime.MinValue;

        // Delegates for placing jobs onto the thread dispatcher.  
        // Used for making asynchronous calls to Twitter so that the UI does not lock up.
        private delegate void NoArgDelegate();
        private delegate void OneIntStringArgDelegate(int arg1, string arg2);
        private delegate void OneArgDelegate(TweetCollection arg);
        private delegate void OneStringArgDelegate(string arg);
        private delegate void OneLongArgDelegate(long id);
        private delegate void OneIntArgDelegate(int userId);
        private delegate void AddTweetsUpdateDelegate(TweetCollection arg);
        private delegate void CreateReplyUpdateDelegate(long id, long cid, string text);
        private delegate void MessagesDelegate(DirectMessageCollection arg);
        private delegate void SendMessageDelegate(string user, string text);
        private delegate void LoginDelegate(User arg);
        private delegate void DeleteTweetDelegate(long id);

        // Settings used by the application
        private Properties.Settings AppSettings = Properties.Settings.Default;

        // booleans to keep track of state
        private bool isExpanded;
        private bool isLoggedIn;
        private bool isRetweetedMessage;
        private bool isReplyMessage;
        private bool isMessageExpanded;
        private bool isReplyExpanded;
        private bool ignoreKey;
        private bool tweetFormattingMayBeRequired;
        private bool isInAutocompleteMode;

        private DateTime? lastTruncatedTweetTime;

        private enum CurrentView
        {
            Recent, Mentions, User, Messages, Replies, More
        }

        private UserCollection friends
        {
            get { return App.friends; }
            set { App.friends = value; }
        }

        private CurrentView currentView
        {
            get
            {
                if (Messages.Visibility == Visibility.Visible)
                {
                    return CurrentView.Messages;
                }
                if (UserTimeline.Visibility == Visibility.Visible)
                {
                    return CurrentView.User;
                }
                return CurrentView.Recent;
            }
        }

        private MoreResults moreResults
        {
            get { return MoreResults.Conversation; }
        }

        private string displayUser;

        public string ScreenName
        {
            get { return displayUser; }
            set { displayUser = value; }
        }
        private int uid;

        public int UserId
        {
            get { return uid; }
            set { uid = value; }
        }
        private int lastUid;
        private string lastDisplayUser;
        private Tweet retweetedTweet;

        private string imageFilePath;

        private static IDictionary<string, EmotionCollection> _emotionDictionary;

        public static IDictionary<string, EmotionCollection> EmotionDictionary
        {
            get { return _emotionDictionary; }
            set { _emotionDictionary = value; }
        }

        private Deployment _clickOnce;
        private System.Windows.Threading.DispatcherTimer _clickOnceUpdateTimer;

        private int popupCount = 0;

        internal Tweet SelectedTweet
        {
            get
            {
                Tweet selectedTweet = null;
                if (null != UserTimelineListBox.SelectedItem) selectedTweet = (Tweet)UserTimelineListBox.SelectedItem;
                else selectedTweet = (Tweet)UserTimelineListBox.Items[0];
                return selectedTweet;
            }
        }

        SoundPlayer _player;
        #endregion

        #region Constructor
        public DesktopWindow()
        {
            this.InitializeComponent();
        }

        private void SetTweetSorting()
        {
            ICollectionView collectionView = CollectionViewSource.GetDefaultView(tweets);
            collectionView.SortDescriptions.Add(new SortDescription("DateCreated", ListSortDirection.Descending));
        }
        #endregion

        void MainWindow_Closing(object sender, CancelEventArgs e)
        {
            // If the user selected to minimize on close and the window state is normal
            // just minimize the app
            if (AppSettings.MinimizeOnClose && this.reallyexit == false)
            {
                e.Cancel = true;
                _storedWindowState = this.WindowState;
                this.WindowState = WindowState.Minimized;
                if (_notifyIcon != null)
                {
                    _notifyIcon.ShowBalloonTip(2000);
                }
            }
        }

        //EssentialWindow必须重载的
        protected override Decorator GetWindowButtonsPlaceholder()
        {
            return WindowButtonsPlaceholder;
        }

        private void Header_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
            {
                this.DragMove();
            }
        }

        #region Retrieve new tweets

        /// <summary>
        /// 封装成函数为了异步取回Recent
        /// </summary>
        private void DelegateRecentFetch()
        {
            // 显示当前状态
            StatusTextBlock.Text = "读取微博...";

            PlayStoryboard("Fetching");

            // 创建一个Dispatcher取回最新的微博
            NoArgDelegate fetcher = new NoArgDelegate(
                this.GetTweets);

            fetcher.BeginInvoke(null, null);

        }

        private void InitializeMiscSettings()
        {
            AppSettings.UserBehaviorManager = new UserBehaviorManager(AppSettings.SerializedUserBehaviors);
            Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
            if (!ApplicationDeployment.IsNetworkDeployed)
            {
                Title = string.Format("Pawing {0}.{1}", version.Major, version.Minor);
#if DEBUG
                Title = Title + string.Format("{0} Debug", version.Revision);
#endif
            }
            else
            {
                // update window with clickonce version number
                this.Title = AppSettings.ApplicationName + " " + ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString();
            }
        }

        private void Timer_Elapsed(object sender, EventArgs e)
        {
            if (ContentBorder.Visibility == Visibility.Visible)
            {
                DelegateMessagesFetch();
            }
        }

        private void GetTweets()
        {
            try
            {
                // Schedule the update functions in the UI thread.
                LayoutRoot.Dispatcher.BeginInvoke(
                    DispatcherPriority.Normal,
                    new OneArgDelegate(UpdateUserInterface), twitter.GetFriendsTimeline());

                // Direct message and replies < 70 hours old will be displayed on the recent tab.
                // Once this somewhat arbitrary (Friday, 5pm - Monday, 9am + 6 hours) threshold is met, 
                // users will still be able to access there direct messages and replies via their
                // respective tabs.  
                //TODO: Make DM and Reply threshold configurable.  Rework this logic once concept of viewed tweets is introduced to Pawing.

                //LayoutRoot.Dispatcher.BeginInvoke(
                //    DispatcherPriority.Loaded,
                //    new OneArgDelegate(UpdateUserInterface), twitter.GetReplies());

                //LayoutRoot.Dispatcher.BeginInvoke(
                //    DispatcherPriority.Loaded,
                //    new OneArgDelegate(UpdateUserInterface), twitter.RetrieveMessages().ToTweetCollection());
            }
            catch (RateLimitException ex)
            {
                App.Logger.Debug(String.Format("从t.sina.com.cn读取微博的过程发生错误: {0}", ex.ToString()));
                LayoutRoot.Dispatcher.BeginInvoke(
                    DispatcherPriority.ApplicationIdle,
                    new OneStringArgDelegate(ShowStatus), ex.Message);
            }
            catch (WebException ex)
            {
                App.Logger.Debug(String.Format("从t.sina.com.cn读取微博的过程发生错误: {0}", ex.ToString()));
            }
            catch (ProxyAuthenticationRequiredException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show("代理服务器没有正确配置，请修改设置菜单中的代理服务器设置。");
            }
            catch (ProxyNotFoundException ex)
            {
                App.Logger.Error("代理服务器没有找到");
                MessageBox.Show(ex.Message);
            }

        }

        /// <summary>
        /// 设置多长时间更新一次微博
        /// </summary>
        private void SetHowOftenToGetUpdatesFromTwitter()
        {
            refreshInterval = new TimeSpan(0, 0, 30);

            refreshTimer.Interval = refreshInterval;
            refreshTimer.Tick += new EventHandler(Timer_Elapsed);
            refreshTimer.Start();
        }

        private void SetDataContextForAllOfTabs()
        {
            // 为所有的Tab设置数据
            //LayoutRoot.DataContext = tweets;
            //TweetsListBox.ItemsSource = tweets;
            //MentionsListBox.ItemsSource = mentions;
            //UserTab.DataContext = userTweets;
            UserTimelineListBox.ItemsSource = userTweets;
            MessagesListBox.ItemsSource = messages;
            //MoreListBox.DataContext = moreTweets;
            //RepliesListBox.ItemsSource = replies;
        }

        private void TrapUnhandledExceptions()
        {
            LayoutRoot.Dispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(Dispatcher_UnhandledException);
        }

        /// <summary>
        /// single instance for release mode
        /// </summary>
        private void SetupSingleInstance()
        {
#if !DEBUG
			Application.Current.Exit += new ExitEventHandler(Current_Exit);
			_instanceManager = new SingleInstanceManager(this, ShowApplication);
#endif
        }


        private void InitializeTwitterNet()
        {
            if (twitter == null)
                twitter = new TwitterNet();

            twitter.TwitterServerUrl = AppSettings.TwitterHost;
            twitter.AccessToken = AppSettings.OAuthToken;
            twitter.AccessTokenSecret = AppSettings.OAuthTokenSecret;
        }

        private void UpdateUserInterface(TweetCollection newTweets)
        {
            DateTime lastUpdated = DateTime.Now;
            StatusTextBlock.Text = "上次更新: " + lastUpdated.ToLongTimeString();

            AppSettings.LastUpdated = lastUpdated.ToString();
            AppSettings.Save();

            FilterTweets(newTweets, true);
            HighlightTweets(newTweets);
            UpdateExistingTweets();

            TweetCollection addedTweets = new TweetCollection();

            //prevents huge number of notifications appearing on startup
            bool displayPopups = !(tweets.Count == 0);

            // Add the new tweets
            for (int i = newTweets.Count - 1; i >= 0; i--)
            {
                Tweet tweet = newTweets[i];

                if (tweets.Contains(tweet) || HasBehavior(tweet, UserBehavior.Ignore) || IsTruncatedTweet(tweet))
                    continue;

                tweets.Add(tweet);
                tweet.Index = tweets.Count;
                tweet.IsNew = true;
                addedTweets.Add(tweet);
            }

            // tweets listbox ScrollViewer.CanContentScroll is set to "False", which means it scrolls more smooth,
            // However it disables Virtualization
            // Remove tweets pass 1000 should improve performance reasons.
            if (AppSettings.KeepLatest != 0)
            {
                if (tweets.Count > AppSettings.KeepLatest)
                    lastTruncatedTweetTime = tweets[AppSettings.KeepLatest - 1].DateCreated;

                tweets.TruncateAfter(AppSettings.KeepLatest);
            }

            if (addedTweets.Count > 0)
            {
                if (AppSettings.DisplayNotifications && !(bool)this.IsActive)
                    NotifyOnNewTweets(addedTweets, "tweet");

                if (AppSettings.PlaySounds)
                {
                    // Author: Keith Elder
                    // I wrapped a try catch around this and added logging.
                    // I found that the Popup screen and this were causing 
                    // a threading issue.  At least that is my theory.  When
                    // new items would come in, and play a sound as well as 
                    // pop a new message there was no need to recreate and load
                    // the wave file.  InitializeSoundPlayer() was added on load
                    // to do that just once.
                    try
                    {
                        // Play tweets found sound for new tweets
                        _player.Play();
                    }
                    catch (Exception ex)
                    {
                        App.Logger.Error("错误的PlaySounds", ex);
                    }
                }
            }

            StopStoryboard("Fetching");
        }


        private void ContextMenuDeleteMessage_Click(object sender, RoutedEventArgs e)
        {
            DeleteDirectMessage();
        }


        private void DeleteDirectMessage()
        {
            DirectMessage message = MessagesListBox.SelectedItem as DirectMessage;
            if (message != null)
            {
                DeleteDirectMessage(message.Id);
                if (messages.Contains(message))
                {
                    messages.Remove(message);
                }
            }
        }

        private void DeleteDirectMessage(long id)
        {
            twitter.DestroyDirectMessage(id);
        }

        private void NotifyOnNewTweets(TweetCollection newTweets, string type)
        {
            if (GrowlCommunicator.IsRunning())
            {
                GrowlNotify(newTweets, type);
            }
            else if (SnarlConnector.GetSnarlWindow().ToInt32() != 0)
            {
                SnarlNotify(newTweets, type);
            }
            else
            {
                PopUpNotify(newTweets);
            }
        }


        private void PopUpNotify(TweetCollection newTweets)
        {
            TweetCollection popUpTweets = new TweetCollection();

            foreach (var tweet in newTweets)
            {
                if (ShouldPopUp(tweet))
                    popUpTweets.Add(tweet);
            }

            if (popUpTweets.Count > Double.Parse(AppSettings.MaximumIndividualAlerts))
            {
                Popup p = new Popup("New Tweets", BuiltNewTweetMessage(popUpTweets), twitter.CurrentlyLoggedInUser.ImageUrl, 0);
                SetupPopupProps(p);
                p.Show();
            }
            else
            {
                int index = 0;
                foreach (Tweet tweet in popUpTweets)
                {
                    Popup p = new Popup(tweet, index++);
                    SetupPopupProps(p);
                    p.Show();
                }
            }
        }


        private void SetupPopupProps(Popup p)
        {
            p.FadeOutFinished += new FadeOutFinishedDelegate(RemovePopup);
            p.Clicked += new PopupClickedDelegate(PopupClicked);
            p.CloseButtonClicked += new PopupCloseButtonClickedDelegate(RemovePopup);
        }



        void PopupClicked(Tweet tweet)
        {
            if (this.WindowState == WindowState.Minimized)
            {
                Show();
                Activate();
                WindowState = _storedWindowState;
            }
        }

        private bool ShouldPopUp(Tweet tweet)
        {
            if (AppSettings.AlertSelectedOnly)
                return HasBehavior(tweet, UserBehavior.AlwaysAlert);

            return (!HasBehavior(tweet, UserBehavior.NeverAlert) || HasBehavior(tweet, UserBehavior.Ignore));

        }

        private bool IsTruncatedTweet(Tweet tweet)
        {
            if (tweet.DateCreated < lastTruncatedTweetTime)
                return true;

            return false;
        }

        private void FilterTweets(TweetCollection tweets, bool filterUsers)
        {
            bool usersToFilter = filterUsers && (ignoredUsers.Count > 0);
            if (string.IsNullOrEmpty(AppSettings.FilterRegex) && !usersToFilter)
                return;

            for (int i = tweets.Count - 1; i >= 0; i--)
            {
                Tweet tweet = tweets[i];
                if (!string.IsNullOrEmpty(AppSettings.FilterRegex) && Regex.IsMatch(tweet.Text, AppSettings.FilterRegex, RegexOptions.IgnoreCase))
                    tweets.Remove(tweet);
                else if (ignoredUsers.ContainsKey(tweet.User.ScreenName) && ignoredUsers[tweet.User.ScreenName] > DateTime.Now)
                    tweets.Remove(tweet);
            }
        }

        private void HighlightTweets(TweetCollection tweets)
        {
            if (string.IsNullOrEmpty(AppSettings.HighlightRegex))
                return;

            foreach (Tweet tweet in tweets)
            {
                if (Regex.IsMatch(tweet.Text, AppSettings.HighlightRegex, RegexOptions.IgnoreCase) ||
                    Regex.IsMatch(tweet.User.ScreenName, AppSettings.HighlightRegex, RegexOptions.IgnoreCase))
                {
                    tweet.IsInteresting = true;
                }
            }
        }

        private void ParoleIgnoredUsers()
        {
            List<string> paroledUsers = new List<string>();
            foreach (KeyValuePair<string, DateTime> ignoredUser in ignoredUsers)
            {
                if (ignoredUser.Value < DateTime.Now.AddHours(6))
                    paroledUsers.Add(ignoredUser.Key);
            }
            paroledUsers.ForEach(userName => ignoredUsers.Remove(userName));
        }

        private bool HasBehavior(Tweet tweet, UserBehavior behavior)
        {
            return AppSettings.UserBehaviorManager.HasBehavior(tweet.User.Name, behavior);
        }

        private static string BuiltNewTweetMessage(TweetCollection newTweets)
        {
            string message = string.Format("你有{0}条新微博\n", newTweets.Count);
            foreach (Tweet tweet in newTweets)
            {
                message += " " + tweet.User.ScreenName;
            }
            if (message.Length > TwitterNet.CharacterLimit)
            {
                message = message.Substring(0, (TwitterNet.CharacterLimit - 5));
                int lastSpace = message.LastIndexOf(' ');
                message = message.Substring(0, lastSpace) + "...";
            }
            return TruncateMessage(message);
        }

        private static string TruncateMessage(string message)
        {
            if (message.Length > TwitterNet.CharacterLimit)
            {
                message = message.Substring(0, (TwitterNet.CharacterLimit - 5));
                int lastSpace = message.LastIndexOf(' ');
                message = message.Substring(0, lastSpace) + "...";
            }
            return message;
        }

        private void SnarlNotify(TweetCollection newTweets, string type)
        {
            string alertClass = "";
            if (type == "reply")
            {
                alertClass = "New reply";
            }
            else if (type == "directMessage")
            {
                alertClass = "New direct message";
            }
            else if (type == "mention")
            {
                alertClass = "New mention";
            }
            else
            {
                alertClass = "New tweet";
            }

            if (newTweets.Count > Double.Parse(AppSettings.MaximumIndividualAlerts))
            {
                string defaultImage = "";
                string tempFile = System.IO.Path.GetTempFileName();
                WebClient client = new WebClient();
                try
                {
                    client.DownloadFile(twitter.CurrentlyLoggedInUser.ImageUrl, tempFile);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    tempFile = defaultImage;
                }


                WindowsMessage replyMsg = new WindowsMessage();

                SnarlConnector.ShowMessageEx("New tweets summarized", "你有新微博！", BuiltNewTweetMessage(newTweets), int.Parse(Properties.Settings.Default.NotificationDisplayTime), tempFile, this.SnarlConfighWnd, replyMsg, "");
                if (tempFile != defaultImage)
                {
                    System.IO.File.Delete(tempFile);
                }
            }
            else
            {
                foreach (Tweet tweet in newTweets)
                {
                    string defaultImage = "";

                    string tempFile = System.IO.Path.GetTempFileName();
                    WebClient client = new WebClient();
                    try
                    {
                        client.DownloadFile(tweet.User.ImageUrl, tempFile);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex);
                        tempFile = defaultImage;
                    }

                    WindowsMessage replyMsg = new WindowsMessage();
                    SnarlConnector.ShowMessageEx(alertClass, tweet.User.ScreenName, string.Format("{0}\n\n{1}", tweet.Text, tweet.RelativeTime), int.Parse(Properties.Settings.Default.NotificationDisplayTime), tempFile, this.SnarlConfighWnd, replyMsg, "");
                    if (tempFile != defaultImage)
                    {
                        System.IO.File.Delete(tempFile);
                    }
                }
            }
        }

        private void GrowlNotify(TweetCollection newTweets, string type)
        {
            Growl.Connector.NotificationType notificationType = null;
            if (type == "reply")
            {
                notificationType = GrowlCommunicator.NewReply;
            }
            else if (type == "directMessage")
            {
                notificationType = GrowlCommunicator.NewDirectMessage;
            }
            else if (type == "mention")
            {
                notificationType = GrowlCommunicator.NewMention;
            }
            else if (newTweets.Count > Double.Parse(AppSettings.MaximumIndividualAlerts))
            {
                notificationType = GrowlCommunicator.NewTweetsSummary;
            }
            else
            {
                notificationType = GrowlCommunicator.NewTweet;
            }

            if (newTweets.Count > Double.Parse(AppSettings.MaximumIndividualAlerts))
            {
                GrowlCommunicator.Notify(notificationType, "你有新微博！", BuiltNewTweetMessage(newTweets), twitter.CurrentlyLoggedInUser.ImageUrl);
            }
            else
            {
                foreach (Tweet tweet in newTweets)
                {
                    GrowlCommunicator.Notify(notificationType, tweet.User.ScreenName, String.Format("{0}\n\n{1}", tweet.Text, tweet.RelativeTime), tweet.User.ImageUrl);
                }
            }
        }

        private void UpdateExistingTweets()
        {
            UpdateExistingTweets(tweets);
        }

        private static void UpdateExistingTweets(TweetCollection oldTweets)
        {
            // Update existing tweets
            foreach (Tweet tweet in oldTweets)
            {
                tweet.IsNew = false;
                tweet.UpdateRelativeTime();
            }
        }



        #endregion

        #region Add new tweet update

        private void UpdateButton_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(TweetTextBox.Text))
            {
                // Schedule posting the tweet

                UpdateButton.Dispatcher.BeginInvoke(
                    DispatcherPriority.Background,
                    new OneStringArgDelegate(AddTweet), TweetTextBox.Text);
            }
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            CancelTweet();
        }

        private void CancelTweet()
        {
            isInAutocompleteMode = false;
            TweetTextBox.Text = string.Empty;
            ToggleUpdate();
        }

        private void ParseTextHereAndTinyUpAnyURLsFound(ref string tweetText)
        {
            //进行网址缩略服务 可惜新浪不提供接口
            ShorteningService service;
            if (!string.IsNullOrEmpty(AppSettings.UrlShorteningService))
                service = (ShorteningService)Enum.Parse(typeof(ShorteningService), AppSettings.UrlShorteningService);
            else
                service = ShorteningService.新浪短链接;

            UrlShorteningService urlHelper = new UrlShorteningService(service);
            tweetText = urlHelper.ShrinkUrls(tweetText);
        }

        private void ScheduleUpdateFunctionInUIThread(TweetCollection addedTweets)
        {
            LayoutRoot.Dispatcher.BeginInvoke(
                            DispatcherPriority.Background,
                            new AddTweetsUpdateDelegate(UpdatePostUserInterface), addedTweets);
        }

        private void AddTweet(string tweetText)
        {
            try
            {
                //bgriswold: Keeping check in place in case final character string is URL and it wasn't reformatted on the fly.
                //if (tweetText.Length > TwitterNet.CharacterLimit) 
                //{
                //    ParseTextHereAndTinyUpAnyURLsFound(ref tweetText);
                //}

                var addedTweets = new TweetCollection();

                string[] statuses = TweetSplitter.SplitTweet(tweetText);
                foreach (string status in statuses)
                {
                    if (isRetweetedMessage)
                    {
                        addedTweets.Add(twitter.AddTweet(status, retweetedTweet.Id));
                    }
                    else if (isReplyMessage)
                    {
                        twitter.AddReply(status, SelectedTweet.Id);
                    }
                    else if (!string.IsNullOrEmpty(imageFilePath))
                    {
                        addedTweets.Add(twitter.AddTweet(status, imageFilePath));
                    }
                    else
                    {
                        addedTweets.Add(twitter.AddTweet(status));
                        //addedTweets.Add(twitter.AddTweet(status, "D:\\Users\\jiangzhuo\\Desktop\\WPB1028_04.JPG"));
                    }
                }

                if (statuses.Length > 0)
                {
                    ScheduleUpdateFunctionInUIThread(addedTweets);
                }

            }
            catch (WebException ex)
            {
                UpdateTextBlock.Text = "更新失败。";
                App.Logger.Debug(String.Format("从t.sina.com.cn读取微博的过程发生错误: {0}", ex.ToString()));
            }
            catch (ProxyAuthenticationRequiredException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show("代理服务器没有正确配置，请修改设置菜单中的代理服务器设置");
            }
            catch (ProxyNotFoundException ex)
            {
                App.Logger.Error("I代理服务器没有找到");
                MessageBox.Show(ex.Message);
            }

        }

        private void UpdatePostUserInterface(TweetCollection addedTweets)
        {
            if (addedTweets != null)
            {
                UpdateTextBlock.Text = "我要说";
                StatusTextBlock.Text = "发布成功";
                PlayStoryboard("CollapseUpdate");
                isExpanded = false;
                isRetweetedMessage = false;
                isReplyMessage = false;
                TweetTextBox.Clear();

                foreach (Tweet tweet in addedTweets)
                {
                    if (tweet.IsDirectMessage)
                    {
                        string dmTarget = GetDMTarget(tweet);
                        StatusTextBlock.Text = string.Format("发送到{0}的信息发送成功", dmTarget);
                    }
                    else
                    {
                        tweets.Insert(0, tweet);
                    }
                }
            }
            else
            {
                App.Logger.Error("发布您的微博到t.sina.com.cn的过程发生错误");
                MessageBox.Show("发布您的微博到t.sina.com.cn的过程发生错误");
            }
        }

        private string GetDMTarget(Tweet tweet)
        {
            Match m = Regex.Match(tweet.Text, @"\b[Dd]\s+(?<dmTarget>\w+)\s+");
            return m.Groups["dmTarget"].Value;
        }

        private void Update_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (ContentBorder.Visibility == Visibility.Visible)
            {
                isInAutocompleteMode = false;
                TweetTextBox.Text = string.Empty;
                isRetweetedMessage = false;
                isReplyMessage = false;
                imageFilePath = string.Empty;
                ToggleUpdate();
            }
        }

        private void ToggleUpdate()
        {
            if (!isExpanded)
            {
                if (null == friends)
                {
                    DispatchFriendsList();
                }

                PlayStoryboard("ExpandUpdate");
                Update.ToolTip = "隐藏发布界面";
                TweetTextBox.Focus();
                isExpanded = true;
            }
            else
            {
                //Keyboard.Focus(CancelButton);
                PlayStoryboard("CollapseUpdate");
                Update.ToolTip = "显示发布界面";
                isExpanded = false;
                isRetweetedMessage = false;
                isReplyMessage = false;
            }
        }
        #endregion


        #region More Tab (conversation, search...etc)
        private enum MoreResults
        {
            Conversation
        }

        private void ViewConversation()
        {
            Tweet selectedTweet = SelectedTweet as Tweet;
            conversationStartId = selectedTweet.Id;
            //this.Tabs.SelectedIndex = 4;
            //DelegateConversationFetch(conversationStartId);


        }

        private void GetConversation(long id)
        {
            try
            {
                // Schedule the update function in the UI thread.
                //LayoutRoot.Dispatcher.BeginInvoke(
                //    DispatcherPriority.Background,
                //    new OneArgDelegate(UpdateMoreInterface), twitter.GetComments(id));
            }
            catch (WebException ex)
            {
                App.Logger.Debug(String.Format("从t.sina.com.cn读取回复的过程发生错误", ex.Message));
            }
            catch (ProxyAuthenticationRequiredException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show("代理服务器没有正确配置，请修改设置菜单中的代理服务器设置");
            }
            catch (ProxyNotFoundException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show(ex.Message);
            }

        }



        #endregion



        #region User Timeline

        private void DelegateUserTimelineFetch(int userId, string screenName)
        {
            uid = userId;
            if (screenName == null)
                displayUser = userId.ToString();
            else
                displayUser = screenName;
            UserContextMenu.IsEnabled = true;  // JMF

            if (lastUid != uid)
            {
                userTweets.Clear();
                lastUid = uid;
                lastDisplayUser = displayUser;
            }

            // Let the user know what's going on
            StatusTextBlock.Text = "读取用户的微博...";

            PlayStoryboard("Fetching");

            // Create a Dispatcher to fetching new tweets
            OneIntStringArgDelegate fetcher = new OneIntStringArgDelegate(this.GetUserTimeline);
            fetcher.BeginInvoke(userId, screenName, null, null);
            //LayoutRoot.Dispatcher.BeginInvoke(
            //    DispatcherPriority.Background,
            //    new OneStringArgDelegate(GetUserTimeline), userId);
        }
        private void DelegateUserTimelineFetch(int userId)
        {
            uid = userId;
            //displayUser = userId;
            UserContextMenu.IsEnabled = true;  // JMF

            userTweets.Clear();
            if (lastUid != uid)
            {
                lastUid = uid;
                lastDisplayUser = displayUser;
            }

            // Let the user know what's going on
            StatusTextBlock.Text = "读取用户的微博中...";

            PlayStoryboard("Fetching");

            // Create a Dispatcher to fetching new tweets
            OneIntArgDelegate fetcher = new OneIntArgDelegate(this.GetUserTimeline);
            fetcher.BeginInvoke(userId, null, null);
            //LayoutRoot.Dispatcher.BeginInvoke(
            //    DispatcherPriority.Background,
            //    new OneStringArgDelegate(GetUserTimeline), userId);
        }

        private void GetUserTimeline(int userId)
        {
            try
            {
                // Schedule the update function in the UI thread.
                LayoutRoot.Dispatcher.BeginInvoke(
                    DispatcherPriority.Background,
                    new OneArgDelegate(UpdateUsersTimelineInterface), twitter.GetUserTimeline(userId));
            }

            // Jason Follas: Added the following UI feedback behavior for when users weren't found.
            catch (UserNotFoundException userNotFoundEx)
            {

                TweetCollection fakeTweets = new TweetCollection();
                fakeTweets.Add(new Tweet());
                fakeTweets[0].Id = -1;
                fakeTweets[0].Text = userNotFoundEx.Message;
                fakeTweets[0].SourceWithOutUrl = "Pawing Error Handler";
                fakeTweets[0].User = new User();
                fakeTweets[0].User.ScreenName = "@" + userNotFoundEx.UserId;
                fakeTweets[0].User.Description = userNotFoundEx.Message;


                StopStoryboard("Fetching");

                this.UserContextMenu.IsEnabled = false;

                UpdateUsersTimelineInterface(fakeTweets);

            }
            catch (System.Security.SecurityException ex)
            {
                App.Logger.DebugFormat("用户不允许访问被保护的微博{0}. 错误详情: {1}", userId, ex.ToString());
                StatusTextBlock.Text = userId + "的微博是受保护的";
                StopStoryboard("Fetching");
            }
            catch (WebException ex)
            {
                App.Logger.DebugFormat("从t.sina.com.cn读取用户的微博过程发生错误: {0}", ex.ToString());
            }
            catch (ProxyAuthenticationRequiredException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show("代理服务器没有正确配置，请修改设置菜单中的代理服务器设置");
            }
            catch (ProxyNotFoundException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show(ex.Message);
            }

        }
        private void GetUserTimeline(int userId, string screenName)
        {
            try
            {
                // Schedule the update function in the UI thread.
                LayoutRoot.Dispatcher.BeginInvoke(
                    DispatcherPriority.Background,
                    new OneArgDelegate(UpdateUsersTimelineInterface), twitter.GetUserTimeline(userId, screenName));
            }

            // Jason Follas: Added the following UI feedback behavior for when users weren't found.
            catch (UserNotFoundException userNotFoundEx)
            {

                TweetCollection fakeTweets = new TweetCollection();
                fakeTweets.Add(new Tweet());
                fakeTweets[0].Id = -1;
                fakeTweets[0].Text = userNotFoundEx.Message;
                fakeTweets[0].SourceWithOutUrl = "Pawing Error Handler";
                fakeTweets[0].User = new User();
                fakeTweets[0].User.ScreenName = "@" + userNotFoundEx.UserId;
                fakeTweets[0].User.Description = userNotFoundEx.Message;


                StopStoryboard("Fetching");

                this.UserContextMenu.IsEnabled = false;

                UpdateUsersTimelineInterface(fakeTweets);

            }
            catch (System.Security.SecurityException ex)
            {
                App.Logger.DebugFormat("用户不允许访问被保护的微博{0}. 错误详情: {1}", userId, ex.ToString());
                StatusTextBlock.Text = userId + "的微博是受保护的";
                StopStoryboard("Fetching");
            }
            catch (WebException ex)
            {
                App.Logger.DebugFormat("从t.sina.com.cn取回用户微博的过程发生错误: {0}", ex.ToString());
            }
            catch (ProxyAuthenticationRequiredException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show("代理服务器没有正确配置，请修改设置菜单中的代理服务器设置");
            }
            catch (ProxyNotFoundException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show(ex.Message);
            }

        }

        /// <summary>
        /// Used to override closings and minimize instead
        /// </summary>
        private void OverrideClosing()
        {
            this.Closing += new CancelEventHandler(MainWindow_Closing);
        }

        private void UpdateUsersTimelineInterface(TweetCollection newTweets)
        {
            if (mentionsLastUpdated == null)
            {
                StatusTextBlock.Text = displayUser + "的微博已更新: " + DateTime.Now.ToLongTimeString();
            }
            else
            {
                StatusTextBlock.Text = displayUser + "的微博已更新: " + mentionsLastUpdated.ToLongTimeString();
            }
            User u = null;

            for (int i = newTweets.Count - 1; i >= 0; i--)
            {
                Tweet tweet = newTweets[i];
                u = tweet.User;

                if (!userTweets.Contains(tweet))
                {
                    //userTweets.Insert(0, tweet);
                    userTweets.Add(tweet);
                    tweet.Index = userTweets.Count;
                    tweet.IsNew = true;
                }
                else
                {
                    // update the relativetime for existing tweets
                    userTweets[i].UpdateRelativeTime();
                }
            }

            if (userTweets.Count > 0)
                UserTimelineListBox.SelectedIndex = 0;



            // JMF: There's an issue with binding where the wrong user's header is sometimes 
            // being displayed.  I think it is related to the fact that these header elements
            // are bound to a property found in each list item, and are probably picking up
            // the object from a previous list before the current list is updated (i.e., a
            // binding race condition?).

            // Manually setting header here as a workaround....
            if (u != null)
            {
                UserImage.Source = new ImageSourceConverter().ConvertFromString(u.ImageUrl) as ImageSource;
                UserImage.ToolTip = "点击隐藏" + u.ScreenName + "的微博";
                FullName.Text = u.FullName;
                FullName.ToolTip = "跳转到" + u.ScreenName + "的新浪官方主页";
                FullName.Tag = u.TwitterUrl;
                MainUserImage.Source = new ImageSourceConverter().ConvertFromString(u.ImageUrl) as ImageSource;
                MainUserImage.ToolTip = "点击 对" + u.ScreenName + "进行操作";
                Description.Text = u.Description;
                SiteUrl.Text = u.SiteUrl;
                Location.Text = u.Location;
            }

            StopStoryboard("Fetching");
        }

        #endregion


        #region Send messages

        private void SendMessageButton_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(MessageUserTextBox.Text) && !string.IsNullOrEmpty(MessageTextBox.Text))
            {
                // Schedule posting the tweet
                UpdateButton.Dispatcher.BeginInvoke(
                    DispatcherPriority.Background,
                    new SendMessageDelegate(SendMessage), MessageUserTextBox.Text, MessageTextBox.Text);
            }
        }

        //在message页面发私信
        private void SendMessage(string user, string messageText)
        {
            try
            {
                twitter.SendMessage(user, messageText);

                // Schedule the update function in the UI thread.
                LayoutRoot.Dispatcher.BeginInvoke(
                    DispatcherPriority.Background,
                    new NoArgDelegate(UpdateMessageUserInterface));
            }
            catch (WebException ex)
            {
                UpdateTextBlock.Text = "发送私信失败";
                App.Logger.Debug(String.Format("发送私信的过程发生错误: {0}", ex.ToString()));
            }
            catch (ProxyAuthenticationRequiredException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show("代理服务器没有正确配置，请修改设置菜单中的代理服务器设置");
            }
            catch (ProxyNotFoundException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show(ex.Message);
            }
            DelegateMessagesFetch();
        }


        #region Messages

        private void DelegateMessagesFetch()
        {
            // Let the user know what's going on
            StatusTextBlock.Text = "正在读取私信...";

            PlayStoryboard("Fetching");

            // Create a Dispatcher to fetching new tweets
            NoArgDelegate fetcher = new NoArgDelegate(
                this.GetMessages);

            fetcher.BeginInvoke(null, null);
        }


        private void GetMessages()
        {
            try
            {

                var results = twitter.RetrieveMessages();
                var addResults = results.Where(e => e.Sender.ScreenName == ScreenName);
                var newResults = new DirectMessageCollection();
                foreach (var r in addResults)
                {
                    newResults.Add(r);
                }

                // Schedule the update function in the UI thread.
                LayoutRoot.Dispatcher.BeginInvoke(
                    DispatcherPriority.Background,
                    new MessagesDelegate(UpdateMessagesInterface), newResults);


                var sentresults = twitter.RetrieveSentMessages();
                var sentaddResults = sentresults.Where(e => e.Recipient.ScreenName == ScreenName);
                var sentnewResults = new DirectMessageCollection();
                foreach (var r in sentaddResults)
                {
                    sentnewResults.Add(r);
                }

                LayoutRoot.Dispatcher.BeginInvoke(
                DispatcherPriority.Background,
                new MessagesDelegate(UpdateMessagesInterface), sentnewResults);
            }
            catch (WebException ex)
            {
                App.Logger.Debug(String.Format("从t.sina.com.cn读取私信的过程发生错误:  {0}", ex.ToString()));
            }
            catch (ProxyAuthenticationRequiredException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show("代理服务器没有正确配置，请修改设置菜单中的代理服务器设置");
            }
            catch (ProxyNotFoundException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show(ex.Message);
            }

        }

        private void UpdateMessagesInterface(DirectMessageCollection newMessages)
        {
            messagesLastUpdated = DateTime.Now;
            StatusTextBlock.Text = "私信上次更新: " + messagesLastUpdated.ToLongTimeString();

            for (int i = newMessages.Count - 1; i >= 0; i--)
            {
                DirectMessage message = newMessages[i];
                if (!messages.Contains(message))
                {
                    messages.Add(message);
                    message.Index = messages.Count;
                    //messages.Insert(0, message);
                    message.IsNew = true;

                }
                else
                {
                    // update the relativetime for existing messages
                    messages[i].UpdateRelativeTime();
                }
            }

            StopStoryboard("Fetching");
        }

        #endregion

        private void UpdateMessageUserInterface()
        {
            UpdateTextBlock.Text = "发送私信";
            StatusTextBlock.Text = "私信发送成功";
            //PlayStoryboard("CollapseMessage");
            //isMessageExpanded = false;
            MessageTextBox.Clear();

            foreach (DirectMessage message in messages)
            {
                message.UpdateRelativeTime();
            }
        }

        private void Message_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //ToggleMessage();
        }

        private void ToggleMessage()
        {
            if (!isMessageExpanded)
            {
                PlayStoryboard("ExpandMessage");
                Message.ToolTip = "隐藏私信发送界面";
                MessageTextBox.Focus();
                isMessageExpanded = true;
            }
            else
            {
                PlayStoryboard("CollapseMessage");
                Message.ToolTip = "显示私信发送界面";
                isMessageExpanded = false;
            }
        }

        #endregion


        #region Misc Methods and Event Handlers

        /// <summary>
        /// This event is VERY important since it traps errors that happen unexpectedly.  Pawing has been unstable
        /// due to the fact that there are actions in the API that don't account for the business rules.  So when 
        /// an action occurs, witty crashes.  This handler traps those errors and logs them.  
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            //TODO: Figure out a better option to do with these unhandled exceptions.  Maybe email them or something?
            App.Logger.Error("发生了未处理的错误", e.Exception);
#if DEBUG
            string error = String.Empty;
            if (e.Exception.InnerException != null)
            {
                error = e.Exception.InnerException.Message;
            }
            else
            {
                error = e.Exception.Message;
            }
            MessageBox.Show("发生了未处理的错误。查看log获取详情\n错误: " + error, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
#endif
            e.Handled = true;
        }

        private void InitializeEmotion()
        {
            NoArgDelegate fetcher = new NoArgDelegate(RetrieveEmotion);
            fetcher.BeginInvoke(null, null);
        }

        private void RetrieveEmotion()
        {
            EmotionDictionary = twitter.GetEmotions();
        }

        /// <summary>
        /// Checks for keyboard shortcuts
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e">EventArgs</param>
        private void MainWindow_OnKeyDown(object sender, KeyEventArgs e)
        {
            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                if (isLoggedIn)
                {
                    switch (e.Key)
                    {
                        case Key.D:
                            CreateDirectMessage();
                            break;
                        case Key.U:
                            ToggleUpdate();
                            break;
                        case Key.R:
                            CreateRetweet();
                            break;
                        case Key.F:
                            CreateReply();
                            break;
                    }
                }
                else
                {
                    if (e.Key == Key.Q) { App.Current.Shutdown(); };
                }
            }
            else
            {
                if (e.Key == Key.F5) { this.Refresh(); };

                if (e.Key == Key.Escape)
                {
                    this.WindowState = WindowState.Minimized;
                }
            }
        }

        private void NameClickedInTweet(object sender, RoutedEventArgs reArgs)
        {
            if (reArgs.OriginalSource is System.Windows.Documents.Hyperlink)
            {
                Hyperlink h = reArgs.OriginalSource as Hyperlink;

                //string userId = h.Tag.ToString();
                int userId = 111111;
                displayUser = h.Tag.ToString();
                DelegateUserTimelineFetch(userId, displayUser);

                reArgs.Handled = true;
            }
        }

        private void HashtagClickedInTweet(object sender, RoutedEventArgs reArgs)
        {
            if (reArgs.OriginalSource is System.Windows.Documents.Hyperlink)
            {
                Hyperlink h = reArgs.OriginalSource as Hyperlink;

                string hashtag = h.Tag.ToString();
                string hashtagUrl = String.Format(Settings.Default.HashtagUrl, Uri.EscapeDataString(hashtag));

                try
                {
                    System.Diagnostics.Process.Start(hashtagUrl);
                }
                catch
                {
                    // TODO: Warn the user? Log the error? Do nothing since Pawing itself is not affected?
                }

                reArgs.Handled = true;
            }
        }

        private void ShowStatus(string status)
        {
            StatusTextBlock.Text = status;
        }



        private void CreateDirectMessage()
        {
            Tweet selectedTweet = SelectedTweet as Tweet;
            if (null != selectedTweet)
            {
                CreateDirectMessage(selectedTweet.User.ScreenName);
            }
        }
        private void CreateDirectMessage(string screenName)
        {
            //其他窗口发私信
            //MessagesTab.IsSelected = true;
            //DelegateMessagesFetch();
            //isMessageExpanded = false;
            //MessageUserTextBox.Text = screenName;
            //ToggleMessage();
        }

        private void MoveTweetTextBoxCursorToEnd()
        {
            TweetTextBox.Select(TweetTextBox.Text.Length, 0);
        }

        private void CreateRetweet()
        {
            //reply to user
            if (null != SelectedTweet)
            {
                retweetedTweet = SelectedTweet;
                CreateRetweet(retweetedTweet);
            }
        }

        private void CreateRetweet(Tweet selectedTweet)
        {
            if (!isExpanded)
            {
                ToggleUpdate();
            }
            isRetweetedMessage = true;
            TweetTextBox.Text = string.Empty;
            //if (!string.IsNullOrEmpty(AppSettings.ReplyPrefix))
            //{
            //    TweetTextBox.Text = AppSettings.ReplyPrefix + " ";
            //    TweetTextBox.Text += "@" + screenName + " ";
            //}
            string message = string.Format("{0} @{1}: {2}", AppSettings.RetweetPrefix, selectedTweet.User.ScreenName, selectedTweet.Text);
            TweetTextBox.Text = message;
            //TweetTextBox.Select(TweetTextBox.Text.Length, 0);
            TweetTextBox.Select(0, 0);
        }

        private void CreateReplyAll()
        {
            List<string> screenNames = new List<string>();

            //reply to users
            if (null != SelectedTweet)
            {
                screenNames.Add(SelectedTweet.User.ScreenName);

                string[] words = SelectedTweet.Text.Split(' ');

                foreach (string word in words)
                {
                    if (word.StartsWith("@"))
                    {
                        screenNames.Add(word.Replace("@", ""));
                    }
                }

                CreateReplyAll(screenNames);
            }

        }

        private void CreateReplyAll(List<string> screenNames)
        {
            if (!isExpanded)
            {
                ToggleUpdate();
            }
            isRetweetedMessage = true;
            TweetTextBox.Text = string.Empty;
            if (!string.IsNullOrEmpty(AppSettings.ReplyPrefix))
                TweetTextBox.Text = AppSettings.ReplyPrefix + " ";

            foreach (string screenName in screenNames)
            {
                if (App.LoggedInUser.ScreenName == screenName)
                {
                    continue;
                }
                TweetTextBox.Text += "@" + screenName + " ";
            }

            TweetTextBox.Select(TweetTextBox.Text.Length, 0);
        }

        private void DeleteTweet()
        {
            if (null != SelectedTweet)
            {
                DeleteTweet(SelectedTweet.Id);
            }
        }

        private void DeleteTweet(long id)
        {

            /* By: Keith Elder
             * You can only destroy a tweet if you are the one that created it
             * or if it is a direct message to you.  This is causing exceptions.
             */
            if (SelectedTweet.User.Id == Settings.Default.UserId)
            {
                if (MessageBoxResult.Yes == MessageBox.Show("你确定想永久删除你的微博？\n删除后不能恢复。 选择否临时删除，选择是永久删除", Settings.Default.ApplicationName, MessageBoxButton.YesNo, MessageBoxImage.Question))
                {
                    //LayoutRoot.Dispatcher.BeginInvoke(
                    //                DispatcherPriority.Background,
                    //                new DeleteTweetDelegate(twitter.DestroyTweet), id);
                    DeleteTweetDelegate delete = new DeleteTweetDelegate(twitter.DestroyTweet);
                    delete.BeginInvoke(id, null, null);
                }
                if (tweets.Contains(SelectedTweet))
                    tweets.Remove(SelectedTweet);
                else if (mentions.Contains(SelectedTweet))
                    mentions.Remove(SelectedTweet);

                if (userTweets.Contains(SelectedTweet))
                    userTweets.Remove(SelectedTweet);
            }
        }

        private void FollowUser()
        {
            if (null != SelectedTweet)
            {
                FollowUser(SelectedTweet.User.Id);
            }
        }

        private void FollowUser(int userId)
        {
            //LayoutRoot.Dispatcher.BeginInvoke(DispatcherPriority.Background,
            //    new OneStringArgDelegate(twitter.FollowUser), username);
            OneIntArgDelegate fether = new OneIntArgDelegate(twitter.FollowUser);
            fether.BeginInvoke(userId, null, null);
            DispatchFriendsList();
        }

        private void RefreshButton_Click(object sender, RoutedEventArgs e)
        {
            this.Refresh();
        }

        private void Refresh()
        {
            switch (currentView)
            {
                case CurrentView.Recent:
                    DelegateRecentFetch();

                    // After a manual refresh, reset the timer
                    refreshTimer.Stop();
                    refreshTimer.Start();

                    break;
                case CurrentView.Mentions:
                    //DelegateMentionsFetch();
                    break;
                case CurrentView.Messages:
                    DelegateMessagesFetch();
                    break;
                case CurrentView.User:
                    if (uid != null)
                    {
                        if (displayUser != null)
                        {
                            DelegateUserTimelineFetch(uid, displayUser);
                        }
                        else
                            DelegateUserTimelineFetch(uid);
                    }
                    break;
                case CurrentView.Replies:
                    //DelegateRepliesFetch();
                    break;
                case CurrentView.More:
                    switch (moreResults)
                    {
                        case MoreResults.Conversation:
                            //DelegateConversationFetch(conversationStartId);
                            break;
                    }
                    break;

            }
        }

        #region Clear Methods

        internal void ClearTweets()
        {
            tweets.Clear();
        }

        internal void ClearMentions()
        {
            mentions.Clear();
        }

        internal void ClearReplies()
        {
            replies.Clear();
        }

        private void Clear()
        {
            switch (currentView)
            {
                case CurrentView.Recent:
                    ClearTweets();
                    break;
                case CurrentView.Mentions:
                    ClearMentions();
                    break;
                case CurrentView.Replies:
                    ClearReplies();
                    break;
            }
        }
        #endregion

        private void CancelAll()
        {
            if (isExpanded)
            {
                CancelTweet();
            }
        }


        private void PlayStoryboard(string storyboardName)
        {
            Object o = TryFindResource(storyboardName);
            if (o != null)
            {
                Storyboard storyboard = (Storyboard)o;
                storyboard.Begin(this);
            }
        }

        private void StopStoryboard(string storyboardName)
        {
            Object o = TryFindResource(storyboardName);
            if (o != null)
            {
                Storyboard storyboard = (Storyboard)o;
                storyboard.Stop(this);
            }
        }

        private void TweetsListBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (e.MouseDevice.DirectlyOver != null && e.MouseDevice.DirectlyOver.GetType() == typeof(TextBlock))
            {
                TextBlock textBlock = (TextBlock)e.MouseDevice.DirectlyOver;

                try
                {
                    ListBox listbox = (ListBox)sender;

                    if ((textBlock.Name == "ScreenName") || (textBlock.Name == "RetweetedStatusScreenName"))
                    {
                        //if (listbox.SelectedItem != null && currentView != CurrentView.User)
                        if (listbox.SelectedItem != null)
                        {
                            Tweet tweet = (Tweet)listbox.SelectedItem;
                            //System.Diagnostics.Process.Start(tweet.User.TwitterUrl);
                            uid = tweet.User.Id;
                            //displayUser = tweet.User.ScreenName;
                            displayUser = textBlock.Text.Trim();
                            if (tweet.User.ScreenName == displayUser)
                            {
                                DelegateUserTimelineFetch(tweet.User.Id, tweet.User.ScreenName);
                            }
                            else
                            {
                                DelegateUserTimelineFetch(tweet.RetweetedStatus.User.Id, displayUser);
                            }
                        }
                    }
                }
                catch (Win32Exception ex)
                {
                    App.Logger.Debug(String.Format("Exception: {0}", ex.ToString()));
                }
            }
        }


        private void MoreTab_LostFocus(object sender, RoutedEventArgs e)
        {
            TabItem tab = (TabItem)sender;
            tab.IsEnabled = false;
            tab.Header = "更多...";
        }


        private void UserTimelineListBox_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            AddConversationMenuItem(sender);
        }

        private void MessagesListBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (e.MouseDevice.DirectlyOver != null)
            {
                if (e.MouseDevice.DirectlyOver.GetType() == typeof(TextBlock))
                {
                    TextBlock textBlock = (TextBlock)e.MouseDevice.DirectlyOver;

                    try
                    {
                        ListBox listbox = (ListBox)sender;

                        if (textBlock.Name == "ScreenName")
                        {
                            if (listbox.SelectedItem != null && currentView != CurrentView.User)
                            {
                                DirectMessage tweet = (DirectMessage)listbox.SelectedItem;

                                //ToggleMessage();
                                MessageUserTextBox.Text = textBlock.Text;
                                MessageTextBox.Focus();
                            }
                        }
                    }
                    catch (Win32Exception ex)
                    {
                        App.Logger.Debug(String.Format("Exception: {0}", ex.ToString()));
                    }
                }
            }
        }

        private void MentionsListBox_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            AddConversationMenuItem(sender);
        }

        private void RepliesListBox_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            AddConversationMenuItem(sender);
        }

        private void TweetsListBox_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            AddConversationMenuItem(sender);
        }

        private void LaunchUrlIfValid(string candidateUrlString)
        {
            if (Uri.IsWellFormedUriString(candidateUrlString, UriKind.Absolute))
            {
                try
                {
                    System.Diagnostics.Process.Start(candidateUrlString);
                }
                catch (Win32Exception ex)
                {
                    App.Logger.Debug(String.Format("Exception: {0}", ex.ToString()));
                }
            }
        }
        private void Url_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            TextBlock textBlock = (TextBlock)sender;
            LaunchUrlIfValid(textBlock.Text);
        }

        private void ScreenName_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            TextBlock textBlock = (TextBlock)sender;
            LaunchUrlIfValid(textBlock.Tag.ToString());
        }

        private void OptionsButton_Click(object sender, RoutedEventArgs e)
        {
            //if (this.Topmost == true)
            //{
            //    this.Topmost = false;
            //    this.Hide();
            //    OptionsButton.Content = "最前";
            //}
            //else
            //{
            //    this.Topmost = true;
            //    OptionsButton.Content = "隐藏";
            //}
            DoubleAnimation animation = new DoubleAnimation(1.0, 0.0, new Duration(TimeSpan.FromSeconds(0.5)));
            this.ContentBorder.BeginAnimation(Border.OpacityProperty, animation);
            ObjectAnimationUsingKeyFrames visibilityAnimation = new ObjectAnimationUsingKeyFrames();
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Collapsed, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            ContentBorder.BeginAnimation(Grid.VisibilityProperty, visibilityAnimation);
        }


        #region Context menu event handlers

        private void ContextMenuRetweet_Click(object sender, RoutedEventArgs e)
        {
            CreateRetweet();
        }

        private void ContextMenuReplyAll_Click(object sender, RoutedEventArgs e)
        {
            CreateReplyAll();
        }

        private void ContextMenuReply_Click(object sender, RoutedEventArgs e)
        {
            if (currentView == CurrentView.Replies)
            {
                //CreateReplyInReplies();
            }
            else
            {
                CreateReply();
            }
        }

        private void ContextMenuIgnore_Click(object sender, RoutedEventArgs e)
        {
            //默认忽略60分钟
            IgnoreUser(60);
            UpdateUserInterface(tweets);
        }
        private void ContextMenuConversation_Click(object sender, RoutedEventArgs e)
        {
            ViewConversation();
        }
        private void IgnoreUser(int ignoreTime)
        {
            Tweet selectedTweet = SelectedTweet as Tweet;
            if (selectedTweet != null)
            {
                ignoredUsers[selectedTweet.User.ScreenName] = DateTime.Now.AddMinutes(ignoreTime);
            }
        }

        private void CreateReply()
        {
            //这以前货不是Reply明明就是再发一条囧
            Tweet selectedTweet = SelectedTweet as Tweet;
            if (selectedTweet != null)
            {
                if (!isExpanded)
                {
                    ToggleUpdate();
                }
                string message = string.Format("{0}@{1}: ", AppSettings.ReplyPrefix, selectedTweet.User.ScreenName);
                isReplyMessage = true;
                message = TruncateMessage(message);
                TweetTextBox.Text = message;
                TweetTextBox.Select(TweetTextBox.Text.Length, 0);
            }
        }

        private void AddConversationMenuItem(object sender)
        {
            try
            {
                ListBox listbox = (ListBox)sender;
                if (listbox.SelectedItem != null && currentView == CurrentView.Recent)
                {
                    Tweet tweet = (Tweet)listbox.SelectedItem;
                    MenuItem menuItem = (MenuItem)listbox.ContextMenu.Items.GetItemAt(4);

                    //if (tweet.InReplyTo != null)
                    //{
                    //    menuItem.Visibility = Visibility.Visible;

                    //}
                    //else
                    //{
                    //    menuItem.Visibility = Visibility.Collapsed;

                    //}

                }

            }
            catch (Win32Exception ex)
            {
                App.Logger.Debug(String.Format("Exception: {0}", ex.ToString()));
            }
        }


        private void ContextMenuDirectMessage_Click(object sender, RoutedEventArgs e)
        {
            CreateDirectMessage();
        }

        private void ContextMenuFollow_Click(object sender, RoutedEventArgs e)
        {
            FollowUser();
        }

        private void ContextMenuDelete_Click(object sender, RoutedEventArgs e)
        {
            DeleteTweet();
        }

        private void ContextMenuClear_Click(object sender, RoutedEventArgs e)
        {
            Clear();
        }

        #endregion

        #region Popup Event Handlers

        private void RemovePopup(Popup popup)
        {
            popupCount--;
            popup.Close();
            popup = null;
        }

        #endregion

        #endregion

        #region Filter

        // Delegate for performing filter in background thread for performance improvements
        private delegate void FilterDelegate();

        /// <summary>
        /// Handles the filtering
        /// </summary>
        private void FilterTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            // Start an async operation that filters the list.
            this.Dispatcher.BeginInvoke(
                DispatcherPriority.ApplicationIdle,
                new FilterDelegate(FilterWorker));
        }

        /// <summary>
        /// Worker method that filters the list.
        /// </summary>
        private void FilterWorker()
        {
            //Use collection view to filter the listbox
            ICollectionView collectionView = CollectionViewSource.GetDefaultView(tweets);

            switch (currentView)
            {
                case CurrentView.Recent:
                    collectionView = CollectionViewSource.GetDefaultView(tweets);
                    break;
                case CurrentView.Mentions:
                    collectionView = CollectionViewSource.GetDefaultView(mentions);
                    break;
                case CurrentView.Messages:
                    collectionView = CollectionViewSource.GetDefaultView(messages);
                    break;
                case CurrentView.User:
                    collectionView = CollectionViewSource.GetDefaultView(userTweets);
                    break;
                case CurrentView.Replies:
                    collectionView = CollectionViewSource.GetDefaultView(replies);
                    break;
                default:
                    collectionView = CollectionViewSource.GetDefaultView(tweets);
                    break;
            }

            if (currentView == CurrentView.Messages)
                // messages aren't tweets
                collectionView.Filter = new Predicate<object>(MessageFilter);
            else
                collectionView.Filter = new Predicate<object>(TweetFilter);
        }

        /// <summary>
        /// Delegate to filter the tweet text and by the tweet user's screenname.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool TweetFilter(object item)
        {
            Tweet tweet = item as Tweet;

            // this will prevent the fade animation from starting when the tweet is filtered
            tweet.IsNew = false;

            return (tweet.Text.ToLower().Contains(FilterTextBox.Text.ToLower()))
                   || (tweet.User.ScreenName.ToLower().Contains(FilterTextBox.Text.ToLower()));
        }

        /// <summary>
        /// Delegate to filter the tweet text and by the tweet user's screenname.
        /// </summary>
        public bool MessageFilter(object item)
        {
            DirectMessage message = item as DirectMessage;
            return (message.Text.ToLower().Contains(FilterTextBox.Text.ToLower()))
                   || (message.Sender.ScreenName.ToLower().Contains(FilterTextBox.Text.ToLower()));
        }

        #endregion

        #region Minimize to Tray

        private System.Windows.Forms.NotifyIcon _notifyIcon;

        void OnClosed(object sender, EventArgs e)
        {
            if (!AppSettings.PersistLogin)
            {
                AppSettings.Username = string.Empty;
                AppSettings.UserId = 0;
                //AppSettings.Password = string.Empty;
                AppSettings.Save();
            }

            _notifyIcon.Dispose();
            _notifyIcon = null;

            if (SnarlConnector.GetSnarlWindow().ToInt32() != 0 && this.SnarlConfighWnd != null)
            {
                SnarlConnector.RevokeConfig(this.SnarlConfighWnd);
            }
            if (this.SnarlConfighWnd != null && snarlComWindow != null)
            {
                snarlComWindow.DestroyHandle();
            }
            System.Environment.Exit(1);
        }

        private WindowState _storedWindowState = WindowState.Normal;

        DispatcherTimer hideTimer = new DispatcherTimer();

        void OnStateChanged(object sender, EventArgs args)
        {
            if (AppSettings.MinimizeToTray)
            {
                if (WindowState == WindowState.Minimized)
                {
                    hideTimer.Interval = new TimeSpan(500);
                    hideTimer.Tick += new EventHandler(HideTimer_Elapsed);
                    hideTimer.Start();
                }
                else
                {
                    _storedWindowState = WindowState;
                }
            }
        }

        private void HideTimer_Elapsed(object sender, EventArgs e)
        {
            this.Hide();
            hideTimer.Stop();
        }

        void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            CheckTrayIcon();
        }

        void m_notifyIcon_Click(object sender, EventArgs e)
        {
            Show();
            WindowState = _storedWindowState;
        }

        void CheckTrayIcon()
        {
            ShowTrayIcon(!IsVisible);
        }

        void ShowTrayIcon(bool show)
        {
            if (_notifyIcon != null)
                _notifyIcon.Visible = show;
        }

        void openMenuItem_Click(object sender, EventArgs e)
        {
            Show();
            WindowState = _storedWindowState;
        }

        void exitMenuItem_Click(object sender, EventArgs e)
        {
            this.reallyexit = true;
            this.Close();
        }

        #endregion

        #region Single Instance
        SingleInstanceManager _instanceManager;

        public void ShowApplication()
        {
            if (this.Visibility == Visibility.Hidden)
            {
                this.Visibility = Visibility.Visible;
            }
        }

        void Current_Exit(object sender, ExitEventArgs e)
        {
            Environment.Exit(0);
        }

        #endregion

        #region Filter and Search

        private void TweetScanButton_Click(object sender, RoutedEventArgs e)
        {
            TweetScanHelper ts = new TweetScanHelper();
            TweetCollection searchResults = ts.GetSearchResults(FilterTextBox.Text);

            // TODO: this should be displayed somewhere else instead of the main tweets listbox.
            for (int i = searchResults.Count - 1; i >= 0; i--)
            {
                Tweet tweet = searchResults[i];
                if (!tweets.Contains(tweet))
                {
                    tweets.Insert(0, tweet);
                    tweet.Index = tweets.Count;
                    tweet.IsNew = true;
                    tweet.IsSearchResult = true;
                }
            }
        }

        private void FilterToggleButton_Unchecked(object sender, RoutedEventArgs e)
        {
            //TODO: fix this
            //TODO: need to remove the search tweets from the main list.
            //foreach (Tweet t in tweets)
            //{
            //    if (t.IsSearchResult)
            //    {
            //        tweets.Remove(t);
            //    }
            //}
        }

        #endregion

        #region Autocomplete Friends
        private void UpdateFriendsList()
        {
            if (isLoggedIn)
            {
                friends = twitter.GetFriends() ?? friends;
                lastFriendsUpdate = DateTime.Now;
            }
        }

        private void SetupFriendsListTimer()
        {
            friendsRefreshTimer.Interval = new TimeSpan(0, 0, 5);
            friendsRefreshTimer.IsEnabled = true;
            friendsRefreshTimer.Start();
            friendsRefreshTimer.Tick += new EventHandler(friendsRefreshTimer_Tick);
        }

        private void DispatchFriendsList()
        {
            new NoArgDelegate(this.UpdateFriendsList).BeginInvoke(null, null);
        }

        void friendsRefreshTimer_Tick(object sender, EventArgs e)
        {
            friendsRefreshTimer.Interval = friendsRefreshInterval;
            DispatchFriendsList();
        }

        private void TweetTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (Key.Escape == e.Key)
            {
                CancelTweet();
                e.Handled = true;
            }
            else if (Keyboard.Modifiers == ModifierKeys.Control && Key.Space == e.Key)
            {
                isInAutocompleteMode = true;
                Suggest(TweetTextBox, AutoSuggestPattern, 0);
                e.Handled = true;
            }

            if (!isInAutocompleteMode) return;

            ShowStatus(string.Empty);

            if (Key.Tab == e.Key)
            {
                ignoreKey = true;
                TweetTextBox.Select(TweetTextBox.Text.Length, 0);
                TweetTextBox.Text += " ";
                e.Handled = true;
                TweetTextBox.Select(TweetTextBox.Text.Length, 0);
            }
            //HACK: need to ignore the keypress for backspace
            else if (Key.Back == e.Key)
            {
                ignoreKey = true;
            }
            else if (Key.Up == e.Key)
            {
                Suggest(TweetTextBox, AutoSuggestPattern, -1);
                e.Handled = true;
            }
            else if (Key.Down == e.Key)
            {
                Suggest(TweetTextBox, AutoSuggestPattern, 1);
                e.Handled = true;
            }
            else
            {
                ignoreKey = false;
            }
        }

        private void TweetTextBox_OnPaste(object sender, DataObjectPastingEventArgs e)
        {
            //只粘贴文本
            if (!e.DataObject.GetDataPresent(typeof(String))) return;
            string pastedText = ((String)e.DataObject.GetData(typeof(String)));

            // If a URL was pasted and we're over the limit, shorten it
            //粘贴的URL使超长的时候
            if (UrlShorteningService.IsUrl(pastedText) && (TweetTextBox.Text.Length + pastedText.Length) > TwitterNet.CharacterLimit)
            {
                if (AttemptTinyURLFormatting(TweetTextBox, TweetTextBox.Text + pastedText))
                    e.CancelCommand();
            }
        }

        private void ReplyTextBox_OnPaste(object sender, DataObjectPastingEventArgs e)
        {
            //只粘贴文本
            if (!e.DataObject.GetDataPresent(typeof(String))) return;
            string pastedText = ((String)e.DataObject.GetData(typeof(String)));
        }

        static Regex AutoSuggestPattern = new Regex(@"(^.*@|^d )(\w*)$");

        private void TweetTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            Suggest(TweetTextBox, AutoSuggestPattern, 0);

            if (TweetTextBox.Text.EndsWith(" ") && TweetTextBox.Text.Length > TwitterNet.CharacterLimit)
            {
                // bgriswold: This routine is executed after a trailing space is entered or pasted. 
                // This implies that a URL which is entered as the final character string will not be reformatted. 
                // It can be assumed, however, that users will quickly come to realized that adding a space 
                // after URLs will trigger reformatting and they will begin doing it intuitively.  
                // Enough rambling about a minor point...
                //缩网址
                //AttemptTinyURLFormatting(TweetTextBox, null);
            }
        }

        //神奇的@提示功能
        private void Suggest(TextBox textBox, Regex matchAndReplace, int offset)
        {
            if (ignoreKey || friends == null) return;

            List<String> currentFriends = new List<string>();
            string selectedText = string.Empty;
            Match matchedText = Match.Empty;
            if (isInAutocompleteMode)
            {
                ignoreKey = true;
                selectedText = textBox.SelectedText;
                textBox.SelectedText = string.Empty;
                ignoreKey = false;
            }

            int length = textBox.Text.Length;
            isInAutocompleteMode = matchAndReplace.IsMatch(textBox.Text);
            if (!isInAutocompleteMode)
            {
                ShowStatus(string.Empty);
                return;
            }

            matchedText = matchAndReplace.Match(textBox.Text);
            int selectedIndex = 0;
            if (matchedText.Success)
            {
                string userEnteredText = matchedText.Groups[2].Value;
                {
                    foreach (User friend in friends)
                    {
                        if (friend.ScreenName.StartsWith(userEnteredText, StringComparison.CurrentCultureIgnoreCase) || userEnteredText.Length == 0)
                            currentFriends.Add(friend.ScreenName);
                    }
                }
                if (currentFriends.Count != 0)
                {
                    currentFriends.Sort();

                    selectedIndex = currentFriends.IndexOf(userEnteredText + selectedText);
                    if (selectedIndex < 0) selectedIndex = 0;
                    selectedIndex += offset;
                    if (selectedIndex < 0) selectedIndex = currentFriends.Count - 1;
                    else if (selectedIndex > (currentFriends.Count - 1)) selectedIndex = 0;

                    ignoreKey = true;
                    textBox.Text = matchAndReplace.Replace(textBox.Text, String.Format("${{1}}{0}", currentFriends[selectedIndex]));
                    textBox.Select(length, textBox.Text.Length - length);
                    ignoreKey = false;

                    ShowStatus(string.Format("{0}个匹配项 - [Up/Down]进行切换, [Tab]确认选择", currentFriends.Count));
                }
            }
        }

        public bool AttemptTinyURLFormatting(TextBox textBox, string tweetText)
        {
            if (string.IsNullOrEmpty(tweetText))
                tweetText = textBox.Text;

            if (tweetText.Length < TwitterNet.CharacterLimit) return false;

            ParseTextHereAndTinyUpAnyURLsFound(ref tweetText);

            if (tweetText == textBox.Text) return false;

            textBox.Text = tweetText;
            textBox.SelectionStart = textBox.Text.Length;

            return true;
        }
        #endregion

        #region Recent的DragDrop操作

        private void Recent_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] droppedFilePaths =
                e.Data.GetData(DataFormats.FileDrop, true) as string[];

                //foreach (string droppedFilePath in droppedFilePaths)
                //{
                //    Dispatcher.BeginInvoke(DispatcherPriority.Input, new System.Threading.ThreadStart(() =>
                //    {
                //        twitter.PostPhoto(new System.IO.FileInfo(droppedFilePath), TweetTextBox.Text);
                //    }));
                //    ShowStatus(System.IO.Path.GetFileNameWithoutExtension(droppedFilePath));
                //}
                foreach (string droppedFilePath in droppedFilePaths)
                {
                    imageFilePath = droppedFilePath;
                    imagePresenter.Source = (ImageSource)(new ImageSourceConverter().ConvertFromString(imageFilePath));
                    imagePresenter.Visibility = Visibility.Visible;
                    ToggleUpdate();
                    TweetTextBox.Focus();
                }
            }
        }

        private void Recent_PreviewDragOver(object sender, DragEventArgs e)
        {
            e.Effects = DragDropEffects.All;
            e.Handled = true;
        }

        #endregion

        #region Replies的DragDrop操作
        private void Replies_PreviewDragOver(object sender, DragEventArgs e)
        {
            e.Effects = DragDropEffects.All;
            e.Handled = true;
        }

        private void Replies_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] droppedFilePaths =
                e.Data.GetData(DataFormats.FileDrop, true) as string[];

                foreach (string droppedFilePath in droppedFilePaths)
                {
                    Dispatcher.BeginInvoke(DispatcherPriority.Input, new System.Threading.ThreadStart(() =>
                    {
                        twitter.PostPhoto(new System.IO.FileInfo(droppedFilePath), TweetTextBox.Text);
                    }));

                    ShowStatus(System.IO.Path.GetFileNameWithoutExtension(droppedFilePath));
                }
            }
        }
        #endregion

        #region 自动边缘吸附 和卷动隐藏

        //作废了 位置移动的时候有点bug
        private void EssentialWindow_LocationChanged(object sender, EventArgs e)
        {
            //if (WindowState != WindowState.Minimized)
            //{
            //    if (System.Windows.Forms.Control.MousePosition.X < 5)
            //    {
            //        if (Height != screenHeight)
            //        {
            //            _height = Height;
            //        }
            //        Top = 0;
            //        Left = 0;
            //        MinHeight = screenHeight;
            //        Height = screenHeight;
            //        //Height = Double.NaN;
            //    }
            //    if (Left > 5 && System.Windows.Forms.Control.MousePosition.X > 5)
            //    {
            //        Height = _height;
            //        MinHeight = 0;
            //    }
            //}
        }

        //进入的时候卷入屏幕
        private void EssentialWindow_MouseEnter(object sender, MouseEventArgs e)
        {
            if ((Left <= 5))
            {
                MoveForm(new Point(0, Top));
            }
            else if ((Width + Left) > (screenWidth - 5))
            {
                MoveForm(new Point(screenWidth - Width, Top));
            }
            else if (Top <= 5)
            {
                MoveForm(new Point(Left, 0));
            }
        }

        //离开的时候卷出屏幕
        private void EssentialWindow_MouseLeave(object sender, MouseEventArgs e)
        {
            if ((Left <= 5) && (System.Windows.Forms.Control.MousePosition.X > Left))
            {
                MoveForm(new Point(5 - Width, Top));
            }

            else if (((Width + Left) >= (screenWidth - 5)) && (System.Windows.Forms.Control.MousePosition.X < (Width + Left)))
            {
                MoveForm(new Point(screenWidth - 5, Top));
            }
            else if ((Top <= 5) && (System.Windows.Forms.Control.MousePosition.Y > Top))
            {
                MoveForm(new Point(Left, 5 - Height));
            }
        }

        private void MoveForm(Point newPos)
        {
            //500ms内移动完
            Point currentPos = new Point(Left, Top);
            if (newPos.X != Left)
            {
                double step = (newPos.X - Left) / 10.0;
                for (int i = 1; i <= 10; i++)
                {
                    Left = currentPos.X + step * i;
                    System.Threading.Thread.Sleep(50);
                }
            }
            else
            {
                double step = (newPos.Y - Top) / 10.0;
                for (int i = 1; i <= 10; i++)
                {
                    Top = currentPos.Y + step * i;
                    System.Threading.Thread.Sleep(50);
                }
            }
        }

        //鼠标移动的时候或者左键放开的时候检测是否吸附 虽然效果不太好
        private void EssentialWindow_MouseMove(object sender, MouseEventArgs e)
        {
            //if (WindowState != WindowState.Minimized)
            //{
            //    if (Left < 5)
            //    {
            //        if (Height != screenHeight)
            //        {
            //            proposeHeight = Height;
            //            proposeWidth = Width;
            //        }
            //        Top = 0;
            //        Left = 0;
            //        MinHeight = screenHeight; Height = screenHeight;
            //        //Height = Double.NaN;
            //    }
            //    if ((Left + Width) > screenWidth - 5)
            //    {
            //        if (Height != screenHeight)
            //        {
            //            proposeHeight = Height;
            //            proposeWidth = Width;
            //        }
            //        Top = 0;
            //        Left = screenWidth-Width;
            //        MinHeight = screenHeight; Height = screenHeight;
            //    }

            //    if (Left > 5)
            //    {
            //        Height = proposeHeight;
            //        MinHeight = proposeHeight;
            //        MaxHeight = proposeHeight;
            //    }
            //    if ((Width + Left) < (screenWidth - 5))
            //    {
            //        Height = proposeHeight;
            //        MinHeight = proposeHeight;
            //        MaxHeight = proposeHeight;
            //    }
            //}
        }
        #endregion


        #region 无按钮自动获取更早的信息

        #region User
        private void UserTimelineListBox_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (((int)(e.VerticalOffset + e.ViewportHeight) >= (int)e.ExtentHeight) && e.VerticalOffset != 0)
            {
                if (UserTimelineListBox.Items.Count < 1000)
                {
                    StatusTextBlock.Text = "正在取回更多" + displayUser + "的微博...";
                    PlayStoryboard("Fetching");
                    NoArgDelegate fetcher = new NoArgDelegate(GetMoreUserTimeline);
                    fetcher.BeginInvoke(null, null);
                }
            }
        }

        private long LastTimelineId;
        private void GetMoreUserTimeline()
        {
            try
            {
                if (LastTimelineId != ((Tweet)UserTimelineListBox.Items[UserTimelineListBox.Items.Count - 1]).Id)
                {
                    LastTimelineId = ((Tweet)UserTimelineListBox.Items[UserTimelineListBox.Items.Count - 1]).Id;
                    LayoutRoot.Dispatcher.BeginInvoke(
                     DispatcherPriority.Background,
                     new OneArgDelegate(UpdateUsersTimelineInterface), twitter.GetUserTimeline(LastTimelineId, uid, displayUser));
                }
            }
            catch (WebException ex)
            {
                App.Logger.Debug(String.Format("从t.sina.com.cn读取用户微博的过程发生错误:  {0}", ex.ToString()));
            }
            catch (ProxyAuthenticationRequiredException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show("代理服务器没有正确配置，请修改设置菜单中的代理服务器设置");
            }
            catch (ProxyNotFoundException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show(ex.Message);
            }
        }
        #endregion


        #region Messages
        private void MessagesListBox_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (((int)(e.VerticalOffset + e.ViewportHeight) >= (int)e.ExtentHeight) && e.VerticalOffset != 0)
            {
                if (MessagesListBox.Items.Count < 1000)
                {
                    StatusTextBlock.Text = "正在取回更多私信...";
                    PlayStoryboard("Fetching");
                    NoArgDelegate fetcher = new NoArgDelegate(GetMoreMessages);
                    fetcher.BeginInvoke(null, null);
                }
            }
        }

        private long LastMessagesId;
        private long LastVisibleId;
        private void GetMoreMessages()
        {
            try
            {
                var results = twitter.RetrieveMessages(LastMessagesId);
                LastMessagesId = results.Last().Id;
                var newResults = new DirectMessageCollection();
                var addResults = results.Where(e => e.Sender.ScreenName != ScreenName);
                foreach (var r in addResults)
                {
                    newResults.Add(r);
                }

                if (LastVisibleId != ((DirectMessage)MessagesListBox.Items[MessagesListBox.Items.Count - 1]).Id)
                {
                    LastVisibleId = ((DirectMessage)MessagesListBox.Items[MessagesListBox.Items.Count - 1]).Id;
                    LayoutRoot.Dispatcher.BeginInvoke(
                        DispatcherPriority.Background,
                        new MessagesDelegate(UpdateMessagesInterface), newResults);
                }
            }
            catch (WebException ex)
            {
                App.Logger.Debug(String.Format("从t.sina.com.cn读取私信的过程发生错误:  {0}", ex.ToString()));
            }
            catch (ProxyAuthenticationRequiredException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show("代理服务器没有正确配置，请修改设置菜单中的代理服务器设置");
            }
            catch (ProxyNotFoundException ex)
            {
                App.Logger.Error("不正确的代理服务器配置");
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #endregion

        #region Drag Trip改变窗口大小

        private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            Point position = Mouse.GetPosition(Application.Current.MainWindow);
            if (position.X > 10 && position.Y > 10)
            {
                this.Height = position.Y;
                this.Width = position.X;
                //this.MinWidth = position.X;
                //this.MaxWidth = position.X;
                proposeWidth = position.X;
                proposeHeight = position.Y;
                //this.MinHeight = position.Y;
                //this.MaxHeight = position.Y;
            }
        }

        private void Thumb_DragOver(object sender, DragEventArgs e)
        {
            //this.MinHeight = double.NaN;
            //this.MaxHeight = double.NaN;
            //this.MinWidth = double.NaN;
            //this.MaxWidth = double.NaN;
        }
        #endregion

        #region 发微添加图片显示

        private void AddPicButton_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog openFileDialog = new System.Windows.Forms.OpenFileDialog();
            openFileDialog.FileOk += new CancelEventHandler(openFileDialog_FileOk);
            openFileDialog.Filter = "图片文件|*.jpg,*.gif,*.png|图片文件(*.jpg)|*.jpg|图片文件(*.gif )|*.gif|图片文件(*.png )|*.png ";
            openFileDialog.ShowDialog();
        }

        private void openFileDialog_FileOk(object sender, CancelEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog openFileDialog = (System.Windows.Forms.OpenFileDialog)sender;
            imageFilePath = openFileDialog.FileName;
            imagePresenter.Source = (ImageSource)(new ImageSourceConverter().ConvertFromString(openFileDialog.FileName));
            imagePresenter.Visibility = Visibility.Visible;
        }
        private void imagePresenter_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            Image imagePresenter = (Image)sender;
            imagePresenter.Opacity = 1.0;
        }

        private void imagePresenter_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            Image imagePresenter = (Image)sender;
            imagePresenter.Opacity = 0.4;
        }

        private void imagePresenter_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            e.Handled = true;
            Image imagePresenter = (Image)sender;
            imageFilePath = string.Empty;
            imagePresenter.Visibility = Visibility.Collapsed;
        }

        #endregion

        #region 表情板相关事件

        private void AddEmotButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            EmotionsBoard emotionBoard = new EmotionsBoard();
            emotionBoard.EmotionClicked += new RoutedEventHandler(emotionBoard_EmotionClicked);
            emotionBoard.Left = this.Left - emotionBoard.Width - 5;
            emotionBoard.Top = this.Top + this.Height - emotionBoard.Height;
            emotionBoard.Owner = this;
            emotionBoard.Show();
        }

        private void emotionBoard_EmotionClicked(object sender, RoutedEventArgs e)
        {
            Emotion emotion = (Emotion)e.OriginalSource;
            if (currentView == CurrentView.User)
            {
                int lastIndex = TweetTextBox.SelectionStart;
                TweetTextBox.Text = TweetTextBox.Text.Insert(lastIndex, emotion.Phrase);
                TweetTextBox.SelectionStart = lastIndex + emotion.Phrase.Length;
            }
            else if (currentView == CurrentView.Messages)
            {
                int lastIndex = MessageTextBox.SelectionStart;
                MessageTextBox.Text = MessageTextBox.Text.Insert(lastIndex, emotion.Phrase);
                MessageTextBox.SelectionStart = lastIndex + emotion.Phrase.Length;
            }
        }
        #endregion

        private void DesktopWindow_Loaded(object sender, RoutedEventArgs e)
        {
            InitializeTwitterNet();

            TrapUnhandledExceptions();

            SetDataContextForAllOfTabs();

            SetHowOftenToGetUpdatesFromTwitter();

            InitializeMiscSettings();

            InitializeEmotion();

            DelegateUserTimelineFetch(uid, displayUser);

            DelegateMessagesFetch();

            SetTweetSorting();

        }

        private void AvatarGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (ContentBorder.Visibility != Visibility.Visible)
            {
                e.Handled = true;
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    iconGrid.Visibility = Visibility.Visible;
                    ObjectAnimationUsingKeyFrames visibilityAnimation = new ObjectAnimationUsingKeyFrames();
                    visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
                    visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
                    iconGrid.BeginAnimation(Grid.VisibilityProperty, visibilityAnimation);
                    DoubleAnimation animation = new DoubleAnimation(iconGrid.Opacity, 1.0, new Duration(TimeSpan.FromSeconds(0.5)));
                    this.iconGrid.BeginAnimation(Grid.OpacityProperty, animation);
                }
            }
            if (ContentBorder.Visibility == Visibility.Visible)
            {
                e.Handled = true;
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    ObjectAnimationUsingKeyFrames visibilityAnimation = new ObjectAnimationUsingKeyFrames();
                    visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
                    visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
                    visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Collapsed, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
                    ContentBorder.BeginAnimation(Border.VisibilityProperty, visibilityAnimation);
                    DoubleAnimation animation = new DoubleAnimation(ContentBorder.Opacity, 0.0, new Duration(TimeSpan.FromSeconds(0.5)));
                    this.ContentBorder.BeginAnimation(Border.OpacityProperty, animation);
                }
            }
            base.DragMove();
        }

        private DesktopWindow desktopWindow;
        private void MessagesListBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && e.MouseDevice.DirectlyOver.GetType() == typeof(Image))
            {
                Image image = (Image)e.OriginalSource;
                if (image.Name == "UserImage")
                {
                    try
                    {
                        ListBox listbox = (ListBox)sender;
                        //QueryContinueDragEventHandler handler=new QueryContinueDragEventHandler(
                        desktopWindow = new DesktopWindow();
                        QueryContinueDragEventHandler handler = new QueryContinueDragEventHandler(this.DragSource_QueryContinueDrag);
                        listbox.QueryContinueDrag += handler;
                        //desktopWindow.Left = this.Left + e.GetPosition(this).X;
                        //desktopWindow.Top = this.Top + e.GetPosition(this).Y;
                        DirectMessage directMessage = image.DataContext as DirectMessage;
                        desktopWindow.ScreenName = directMessage.Sender.ScreenName;
                        desktopWindow.UserId = directMessage.Sender.Id;
                        desktopWindow.Show();
                        DragDrop.DoDragDrop(listbox, "", DragDropEffects.Move);
                        listbox.QueryContinueDrag -= handler;
                    }
                    catch (Exception)
                    {
                    }
                }
            }
        }

        private void DragSource_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            Win32.POINT point = new Win32.POINT();
            if ((this.desktopWindow != null) && Win32.GetCursorPos(out point))
            {
                this.desktopWindow.Left = point.X - 264 - 30;
                this.desktopWindow.Top = point.Y - 264 - 30;
            }
        }

        private void userTimelineIcon_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            //UserTimeline
            ContentBorder.Margin = (Thickness)(new ThicknessConverter().ConvertFromString("252,191,-1,-1"));
            ContentBorder.Visibility = Visibility.Visible;

            DoubleAnimation hideAnimation = new DoubleAnimation(1.0, 0.0, new Duration(TimeSpan.FromSeconds(0.5)));
            this.iconGrid.BeginAnimation(Image.OpacityProperty, hideAnimation);
            ObjectAnimationUsingKeyFrames visibilityAnimation = new ObjectAnimationUsingKeyFrames();
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Collapsed, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            iconGrid.BeginAnimation(Border.VisibilityProperty, visibilityAnimation);

            ObjectAnimationUsingKeyFrames visibilityVisibleAnimation = new ObjectAnimationUsingKeyFrames();
            visibilityVisibleAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
            visibilityVisibleAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            ContentBorder.BeginAnimation(Border.VisibilityProperty, visibilityVisibleAnimation);

            ContentBorder.Visibility = Visibility.Visible;
            UserTimeline.Visibility = Visibility.Visible;
            Messages.Visibility = Visibility.Collapsed;

            DoubleAnimation animation = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(0.5)));
            //if (ContentBorder.Opacity == 0.0)
            //{
            this.ContentBorder.BeginAnimation(Border.OpacityProperty, animation);
            //}
        }

        private void messageIcon_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            //DirectMesage
            ContentBorder.Margin = (Thickness)(new ThicknessConverter().ConvertFromString("2,1,245,317"));
            ContentBorder.Visibility = Visibility.Visible;

            DoubleAnimation hideAnimation = new DoubleAnimation(1.0, 0.0, new Duration(TimeSpan.FromSeconds(0.5)));
            this.iconGrid.BeginAnimation(Grid.OpacityProperty, hideAnimation);
            ObjectAnimationUsingKeyFrames visibilityAnimation = new ObjectAnimationUsingKeyFrames();
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Collapsed, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            iconGrid.BeginAnimation(Grid.VisibilityProperty, visibilityAnimation);

            ObjectAnimationUsingKeyFrames visibilityVisibleAnimation = new ObjectAnimationUsingKeyFrames();
            visibilityVisibleAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
            visibilityVisibleAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            ContentBorder.BeginAnimation(Border.VisibilityProperty, visibilityVisibleAnimation);

            ContentBorder.Visibility = Visibility.Visible;
            UserTimeline.Visibility = Visibility.Collapsed;
            Messages.Visibility = Visibility.Visible;
            DoubleAnimation animation = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(0.5)));
            //if (ContentBorder.Opacity == 0.0)
            //{
            this.ContentBorder.BeginAnimation(Border.OpacityProperty, animation);
            //}

            MessageUserTextBox.Text = ScreenName;
        }

        private void iconGrid_MouseLeave(object sender, MouseEventArgs e)
        {
            if (iconGrid.Opacity != 0.0)
            {
                DoubleAnimation hideAnimation = new DoubleAnimation(1.0, 0.0, new Duration(TimeSpan.FromSeconds(0.8)));
                this.iconGrid.BeginAnimation(Grid.OpacityProperty, hideAnimation);
            }
            if (iconGrid.Visibility == Visibility.Visible)
            {
                ObjectAnimationUsingKeyFrames visibilityAnimation = new ObjectAnimationUsingKeyFrames();
                visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
                visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.8000000"))));
                visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Collapsed, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.8000000"))));
                iconGrid.BeginAnimation(Grid.VisibilityProperty, visibilityAnimation);
            }
        }

        private void closeIcon_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            //DoubleAnimation closeAnimation = new DoubleAnimation(1.0, 0.0, new Duration(TimeSpan.FromSeconds(0.5)));
            //this.BeginAnimation(EssentialWindow.OpacityProperty, closeAnimation);
            //closeAnimation.Completed += new EventHandler(closeAnimation_Completed);
            this.PlayStoryboard("CloseAnimation");
        }

        private void CloseAnimation_Completed(object sender, EventArgs e)
        {
            this.Close();
        }

        private void iconGrid_MouseEnter(object sender, MouseEventArgs e)
        {
            if (iconGrid.Opacity != 0.0)
            {
                DoubleAnimation showAnimation = new DoubleAnimation(iconGrid.Opacity, 1.0, new Duration(TimeSpan.FromSeconds(0.5)));
                this.iconGrid.BeginAnimation(Grid.OpacityProperty, showAnimation);
            }
            ObjectAnimationUsingKeyFrames visibilityAnimation = new ObjectAnimationUsingKeyFrames();
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.8000000"))));
            iconGrid.BeginAnimation(Grid.VisibilityProperty, visibilityAnimation);
        }

        private void recommendIcon_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            e.Handled = true;
            //UserTimeline
            ContentBorder.Margin = (Thickness)(new ThicknessConverter().ConvertFromString("252,191,-1,-1"));
            ContentBorder.Visibility = Visibility.Visible;

            DoubleAnimation hideAnimation = new DoubleAnimation(1.0, 0.0, new Duration(TimeSpan.FromSeconds(0.5)));
            this.iconGrid.BeginAnimation(Image.OpacityProperty, hideAnimation);
            ObjectAnimationUsingKeyFrames visibilityAnimation = new ObjectAnimationUsingKeyFrames();
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            visibilityAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Collapsed, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            iconGrid.BeginAnimation(Border.VisibilityProperty, visibilityAnimation);

            ObjectAnimationUsingKeyFrames visibilityVisibleAnimation = new ObjectAnimationUsingKeyFrames();
            visibilityVisibleAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("0:0:0"))));
            visibilityVisibleAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, (KeyTime)(new KeyTimeConverter().ConvertFromString("00:00:00.5000000"))));
            ContentBorder.BeginAnimation(Border.VisibilityProperty, visibilityVisibleAnimation);

            ContentBorder.Visibility = Visibility.Visible;
            UserTimeline.Visibility = Visibility.Visible;
            Messages.Visibility = Visibility.Collapsed;

            DoubleAnimation animation = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(0.5)));
            //if (ContentBorder.Opacity == 0.0)
            //{
            this.ContentBorder.BeginAnimation(Border.OpacityProperty, animation);
            //}
        }

    }

}
